<?php

namespace app\company\controller;

use app\common\enum\purchase\CheckStatus;
use app\common\service\annotation\ControllerAnnotation;
use app\common\service\annotation\NodeAnnotation;
use app\common\controller\CompanyController;
use app\common\enum\purchase\CheckType;
use app\company\model\CheckStock as CheckStockModel;
use app\company\model\CheckStockDetail;
use app\common\model\DealerGoods;
use app\common\model\DealerGoodsSpec;
use app\Request;
use jianyan\excel\Excel;
use think\App;
use think\facade\Db;
use think\response\Json;

/**
 * @ControllerAnnotation (title="盘点")
 */
class CheckStock extends CompanyController
{
    private CheckStockDetail $detail_model;

    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->model        = new CheckStockModel();
        $this->detail_model = new CheckStockDetail();
        $this->sort         = ['id' => 'desc'];
    }

    public function list(): Json
    {
        [,$where] = $this->buildSearchParams();
        $get  = $this->request->get();
        $list = $this->model->with(['detail', 'create_user', 'check_user'])
                            ->where($where)
                            ->where($this->defaultWhere)->order($this->sort)
                            ->paginate($get['limit'] ?? 15)->each(function ($item){
                                // 盘盈数量
                                $item->py_num = $item->detail()->where('diff_num','>',0)->sum('diff_num');
                                // 盘盈金额
                                $item->py_money = $item->detail()->where('diff_num','>',0)->sum('diff_price');
                                $item->py_color = 'rgba(90, 159, 244, 1)';
                                // 盘亏数量
                                $item->pk_num = $item->detail()->where('diff_num','<',0)->sum('diff_num');
                                // 盘亏金额
                                $item->pk_money = $item->detail()->where('diff_num','<',0)->sum('diff_price');
                                $item->pk_color = 'rgba(245,108, 108, 1)';
                            });
        return $this->success($list);
    }

    public function detail($id): Json
    {
        $get  = $this->request->get();
        $list = $this->detail_model->with([
                                                  'goods' => function ($query) use ($get)
                                                  {
                                                      $query->field('id,name')->with([
                                                          'spec'=>function ($query) {
                                                              $query->field('id,name,unit,dealer_goods_id,ratio,sale_price')->withTrashed();
                                                          }
                                                      ])->withTrashed();
                                                  },
                                                  'spec'  => function ($query)
                                                  {
                                                      $query->field('id,name,unit')->withTrashed();
                                                  },
                                          ])
                                   ->field('CheckStockDetail.id,check_stock_id,dealer_goods_id,dealer_goods_spec_id,
                                   num,check_num,CheckStockDetail.remark,CheckStockDetail.create_time,CheckStockDetail.diff_num,CheckStockDetail.diff_price')
                                   ->where('check_stock_id', $id)
                                   ->hasWhere('goods',function ($goods) use ($get){
                                       if(!empty($get['goods_name'])) $goods->where('name','like','%'.$get['goods_name'].'%');
                                   });
        if(empty($get['limit'])){
            $list = $list->select();
        }else{
            $list = $list->paginate($get['limit'] ?? 15);
        }
        $list = $list->each(function ($item){
            $item->color = $item->diff_num >= 0 ? ($item->diff_num > 0 ? 'rgba(90, 159, 244, 1)' : 'rgba(0, 0, 0, 1)' ) : 'rgba(245,108, 108, 1)';
            $this->dealStock($item);
        });
        return $this->success($list);
    }

    public function dealStock($item): void
    {
        $spec = json_decode($item->goods->spec()->select(), true);
        usort($spec, function ($a, $b) {
            return $b['ratio'] <=> $a['ratio'];  // 使用太空船操作符进行升序排序
        });
        $str = $check_str = '';
        $stock = $item->num;
        $check_stock = $item->check_num;
        foreach ($spec as $value){
            if(!$value['ratio']) continue;
            // 原库存
            $quotient = intdiv($stock, $value['ratio']);
            $stock = $stock % $value['ratio'];
            $str .= $quotient.$value['unit'];
            // 盘点库存
            $check_quotient = intdiv($check_stock, $value['ratio']);
            $check_stock = $check_stock % $value['ratio'];
            $check_str .= $check_quotient.$value['unit'];
        }
        $item->num = $str;
        $item->check_num = $check_str;
    }

    /**
     * @NodeAnnotation (title="新增盘点单")
     * @param Request $request
     * @return Json
     */
    public function add(Request $request): Json
    {
        $this->checkPost();
        $post = $request->post();
        try {
            $this->model->transaction(function () use ($post)
            {
                // 组装盘点单主表
                $data  = [
                        'company_id'     => $this->companyId,
                        'no'     => generateOrderNo('PD'),
                        'salesman_id'    => $post['salesman_id'],
                        'dealer_id'      => $post['dealer_id'],
                        'create_user_id' => $this->uid,
                        'check_type'     => $post['check_type'],
                        'check_status'   => CheckStatus::WAIT,
                        'dealer_cate_id' => $post['check_type'] == CheckType::CATE ? $post['dealer_cate_id'] : 0,
                ];
                $where = [
                        ['dealer_id', '=', $post['dealer_id']],
                        ['status', '=', 1],
                ];
                // 判断前端的传来的盘点类型，如果是品类盘，增加筛选条件
                if ($post['check_type'] == CheckType::CATE) {
                    $where[] = ['dealer_cate_id', '=', $post['dealer_cate_id']];
                }
                // 组装盘点商品数据 TODO 可以优化查询组装商品的逻辑
//                $dealerGoodsIds  = (new DealerGoods())->where($where)->column('id');
//                $dealerGoodsSpec = (new DealerGoodsSpec())->where('dealer_goods_id', 'in', $dealerGoodsIds)->select();
                $dealerGoods  = (new DealerGoods())->where($where)->select();
                $detailData      = [];
                $this->model->save($data);
                foreach ($dealerGoods as $goods) {
                    $detailData[] = [
                            'check_stock_id'       => $this->model->id,
                            'dealer_id'            => $post['dealer_id'],
                            'dealer_goods_id'      => $goods['id'],
//                            'dealer_goods_spec_id' => $spec['id'],
                            'num'                  => $goods['warehouse_stock'],
                            'check_num'            => $goods['warehouse_stock'],
                            'diff_num'             => 0,
//                            'sale_price'           => $goods['sale_price'],
//                            'diff_price'           => 0,
                            'remark'               => '',
                    ];
                }
                $this->detail_model->saveAll($detailData);
            });
        } catch (\Exception $e) {
            return $this->error('创建失败' . $e->getMessage());
        }
        return $this->success('创建成功');
    }

    /**
     * @NodeAnnotation (title="修改盘点后库存数量")
     * @param Request $request
     * @return Json
     */
    public function modify(Request $request): Json
    {
        $this->checkPost();
        $post = $request->post();
        $rule = [
                'id'    => 'require|integer',
        ];
        $this->validate($post, $rule);
        $info = $this->detail_model->find($post['id']);
        $details = $post['spec'];
        $stock = 0;
        foreach ($details as $spec){
            $stock += $spec['num'] * $spec['ratio'];
        }
        $specInfo = (new DealerGoodsSpec())->where('dealer_goods_id',$post['dealer_goods_id'])->where('unit_type',1)->find();
        $diffNum = $stock - $info->num;
        $diffPrice = bcmul($diffNum, $specInfo->sale_price, 2);
        $this->detail_model->where('id', $post['id'])->save(['check_num' => $stock, 'diff_num' => $diffNum, 'diff_price' => $diffPrice,'check_status'=> \app\company\model\CheckStock::CHECK_STATUS_YES]);
        return $this->success('修改成功');
    }

    /**
     * @NodeAnnotation (title="盘点审核")
     * @param Request $request
     * @return Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function check(Request $request): Json
    {
        // 每次失去焦点就调一次方法修改盘点单数量，最后统一改库存和盘点表状态
        // 或者是审核一次性更新盘点单数量、更新库存、盘点表状态
        $this->checkPost();
        $post      = $request->post();
        $checkInfo = $this->model->with('detail')->find($post['id']);
        if (!$checkInfo || $checkInfo->check_status != CheckStatus::WAIT) {
            return $this->error('盘点单不符合审核！');
        }
        foreach ($checkInfo->detail as $detail) {
            // 遍历修改商品库存
            if($detail['check_status'] == \app\company\model\CheckStock::CHECK_STATUS_YES)(new DealerGoods())->where('id', $detail->dealer_goods_id)->save(['sales_stock' => $detail->check_num,'warehouse_stock'=>$detail->check_num]);
        }
        // 修改盘点单状态
        (new CheckStockModel())->where('id', $post['id'])->save(['check_status' => CheckStatus::DONE, 'check_user_id' => $this->uid, 'check_time' => time()]);
        return $this->success('盘点成功');
    }

    /**
     * @NodeAnnotation(title="导出")
     * @return bool
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function export(): bool
    {
        $get  = $this->request->get();
        // 构建查询
        $model = new CheckStockDetail();
        // 设置表头
        $header = [
            ['商品名','goods_name'],
            ['单位','unit'],
            ['规格','spec_name'],
            ['原库存','num'],
            ['盘点后库存','check_num'],
            ['记录时间','create_time'],
        ];
        $list = $model->field('id,num,check_num,create_time,dealer_goods_id,dealer_goods_spec_id')->with(['goods','spec'])
            ->where('check_stock_id', $get['id'])
//            ->order('id', 'desc')
            ->select()->each(function ($item){
                $specInfo = (new DealerGoodsSpec())->where('dealer_goods_id',$item->dealer_goods_id)->order('unit_type asc')->withTrashed()->find();
                $item->goods_name = $item->goods->name;
                $item->unit = $specInfo->unit;
//                $item->unit = $item->spec->unit;
//                $item->spec_name = $item->spec->name;
                $item->spec_name = $specInfo->name;
            })
            ->toArray();
        $fileName = '盘点单--'.time();
        return Excel::exportData($list, $header, $fileName, 'xlsx');
    }
}